#include "SBCP.h"
#include <string.h>
#include <stdio.h>
using namespace std;

#define null 0

int min_value(int x, int y) {
	return (x < y)?x:y;
}

buffer encode(struct Packet p) {
	buffer result;
	result.size = 0;
	// Get size info from header
	result.size += p.header->length;

	result.mem = new char[result.size+1];
	char * mem = result.mem;
	// Copy in data from header
	memcpy(mem, p.header, sizeof(struct HDR));
	mem += sizeof(struct HDR);
	// Copy in data from attributes
	List* attribute = p.attr_list;
	while(attribute != null) {
		memcpy(mem, attribute->attributes.hdr, sizeof(struct attr_hdr));
		mem += sizeof(struct attr_hdr);
		memcpy(mem, attribute->attributes.message,
				attribute->attributes.message_length);
		mem += attribute->attributes.message_length;
		attribute = attribute->next;
	}
	result.mem[result.size] = null;
	return result;
}

/* Build a packet with one attribute */
Packet build_packet(int hdr_type, int attr_type, char * input) {
	Packet p;
	int length = strlen(input);
	p.header = (struct HDR*) new char[sizeof(struct HDR)];
	p.header->type = hdr_type;
	p.header->length = sizeof(struct HDR) + sizeof(struct attr_hdr) + length;
	p.attr_list = (struct List*) new char[sizeof(struct List)];
	p.attr_list->attributes.hdr = (struct attr_hdr*) new char[sizeof(struct attr_hdr)];
	p.attr_list->attributes.hdr->length = length + sizeof(struct attr_hdr);
	p.attr_list->attributes.hdr->type = attr_type;
	p.attr_list->attributes.message_length = length;
	p.attr_list->attributes.message = new char[length];
	p.attr_list->next = null;
	memcpy(p.attr_list->attributes.message, input, length);
	return p;
}

// build a packet with two attributes (USE FOR THE HIGH_LEVEL_INI AND LOW_LEVEL_INI)
Packet build_packet(int hdr_type, int attr_type1, char * input1, int attr_type2, char * input2) {
	Packet p = build_packet(hdr_type, attr_type1, input1);
	int length = strlen(input2);
	List* attr2 = (List*) new char[sizeof(List)];
	attr2->attributes.hdr = (attr_hdr*) new char[sizeof(attr_hdr)];
	attr2->attributes.hdr->length = sizeof(attr_hdr) + length;
	attr2->attributes.hdr->type = attr_type2;
	attr2->attributes.message_length = length;
	attr2->attributes.message = new char[length];
	attr2->next = null;
	memcpy(attr2->attributes.message, input2, length);
	p.attr_list->next = attr2;
	p.header->length += attr2->attributes.hdr->length; 
	return p;
}

Packet build_statistic_list(map<int, char*> statistic_data) {
	Packet p;
	p.header = (struct HDR*) new char[sizeof(struct HDR)];
	p.header->type = ACK;
	// Get initial size without usernames
	p.header->length = sizeof(struct HDR);
	
	// Generate record of usernames
	p.attr_list = (struct List*) new char[sizeof(struct List)];
	struct List* next = p.attr_list;
	map<int, char*>::iterator namemap_it;
	int flag = 0;
	for(int i = 0; i < statistic_data.size(); i++) {
		if(statistic_data[i]!=null){
			flag = 1;
			next->attributes.hdr = (struct attr_hdr*) new char(sizeof(struct attr_hdr));
			next->attributes.hdr->type = STATISTIC_DATA;
			next->attributes.hdr->length = sizeof(struct attr_hdr) + strlen(statistic_data[i]);
			next->attributes.message_length = strlen(statistic_data[i]);		
			next->attributes.message = statistic_data[i];
			// update packet header size
			p.header->length += next->attributes.hdr->length;
			if(i < statistic_data.size()-1) {
				next->next = (struct List*) new char[sizeof(struct List)];
				next = next->next;
			}else {
				next->next = null;
			}
		}
		if(flag = 0){
			p.attr_list->next = null;
		}
		
	}
	return p;
}

char* getmessage(char* sock_message){
	struct HDR* _hdr = (struct HDR*)new char[sizeof(struct HDR)];
	struct attr_hdr* _attr_hdr = (struct attr_hdr*)new char[sizeof(struct attr_hdr)];
	memcpy(_hdr, sock_message, sizeof(struct HDR));
	sock_message+=sizeof(struct HDR);
	memcpy(_attr_hdr, sock_message, sizeof(struct attr_hdr));
	sock_message+=sizeof(struct attr_hdr);
	int length =_attr_hdr->length-sizeof(struct attr_hdr);
	char* message=new char[length];
	memcpy(message, sock_message, length);
	return message;
}

char* getnextmessage(char* sock_message){
	struct HDR* _hdr = (struct HDR*)new char[sizeof(struct HDR)];
	struct attr_hdr* _attr_hdr1 = (struct attr_hdr*)new char[sizeof(struct attr_hdr)];
	struct attr_hdr* _attr_hdr2 = (struct attr_hdr*)new char[sizeof(struct attr_hdr)];
	memcpy(_hdr, sock_message, sizeof(struct HDR));
	sock_message+=sizeof(struct HDR);
	memcpy(_attr_hdr1, sock_message, sizeof(struct attr_hdr));
	sock_message+=_attr_hdr1->length;
	memcpy(_attr_hdr2, sock_message, sizeof(struct attr_hdr));
	sock_message+=sizeof(struct attr_hdr);
	int length =_attr_hdr2->length-sizeof(struct attr_hdr);
	char* message=new char[length];
	memcpy(message, sock_message, length);
	return message;
}


std::map<int,char*> get_statistic_data_list(char* sock_message){
	map <int, char*> statistic_data_list;
	struct HDR* _hdr = (struct HDR*)new char[sizeof(struct HDR)];
	struct attr_hdr* _attr_hdr = (struct attr_hdr*)new char[sizeof(struct attr_hdr)];
	memcpy(_hdr, sock_message, sizeof(struct HDR));
	sock_message+=sizeof(struct HDR);
	int length = 0;
	//memcpy(_attr_hdr, sock_message, sizeof(struct attr_hdr));
	//sock_message+=sizeof(struct attr_hdr);
	//int length =_attr_hdr->length-sizeof(struct attr_hdr);
	//char* message=new char[length];
	//memcpy(message, sock_message, length);
	//sock_message+=length;
	int current_location =  sizeof(struct HDR);
	int i=0;
	while(1){
		if(current_location<_hdr->length){
			_attr_hdr = (struct attr_hdr*)new char[sizeof(struct attr_hdr)];
			memcpy(_attr_hdr, sock_message, sizeof(struct attr_hdr));
			sock_message+=sizeof(struct attr_hdr);
			length =_attr_hdr->length-sizeof(struct attr_hdr);
			char* message=new char[length];
			memcpy(message, sock_message, length);
			statistic_data_list.insert(pair<int,char*>(i,message));
			i = i+1;
			sock_message+=length;
			current_location += _attr_hdr->length;	
		}else{
			break;		
		}
	}
	return statistic_data_list;
}

int gettype(char* sock_message){
	struct HDR* _hdr = (struct HDR*)new char[sizeof(struct HDR)];
	memcpy(_hdr, sock_message, sizeof(struct HDR));
	return _hdr->type;
}
